#登录相关
from django import forms
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from utils.encrypt import md5
from web import models
from django_redis import get_redis_connection


#登录函数 :定义forms类 解决数据为空校验问题
#要校验什么字段 放在里面 角色 账户 密码
class LoginForm(forms.Form):
    '''
    相当于一个下拉列表的HTML 参数widget是样式
    <select class="form-control" name="role">
              <option value="2">客户</option>
              <option value="1">管理员</option>
    </select>
    '''
    role = forms.ChoiceField(
        label="角色",
        required=True,# 表示必须填写
        choices=(("1","管理员"),("2","客户")),
        widget=forms.Select(attrs={'class':'form-control'}))
    # 一个文本输入框的html 参数initial为文本框默认值 widget= forms.TextInput 插件用这个生成input标签
    #<input type="text" class="form-control" id="exampleInputEmail1" placeholder="用户名" name="username">#}
    username = forms.CharField(
        label="用户名",
        initial="用户名",
        widget=forms.TextInput(attrs={'class':'form-control',"placeholder":"用户名"}),
        required=True,  # 表示必须填写 默认为T 可以不写这个参数
        )
    #一个密码输入框 # render_value 保留错误的密码 默认不保留
    #<input type="password" class="form-control" id="exampleInputEmail2" placeholder="密码" name="password">
    password = forms.CharField(label="密码",
        #正则校验
        # validators=[RegexValidator(r'^[0-9]+$','密码需要是数值')],
        required=True,# 表示必须填写
        widget=forms.PasswordInput(attrs={'class':'form-control',"placeholder":"密码"},
        render_value=True)
        )
    #自定义校验函数username字段
    def clean_username(self):
        user = self.cleaned_data["username"] #之前校验过的值
        if len(user) < 3 :
            raise ValidationError("校验失败的错误")
        #必须返回验证的数据
        return user
    #password字段
    def clean_password(self):
        print("加密之前的密码",self.cleaned_data["password"])
        # 使用加密函数加密 并返回数据
        return md5(self.cleaned_data["password"])

    #对所有值进行校验 不要轻易返回值 否则最终结果就是它的返回值
    def clean(self):
        #1 无论前面的字段校验是否成功 都会执行clean
        #2 不返回任何值 用之前每个字段校验的返回值，如clean_password的返回
        #3 有返回值 那么会赋值给self。cleaned_data
        #4 可以报错 给到 self.add_error(None, e)
        # raise ValidationError("整体错误")
        pass

    #对字段做最后的修改 返回值没有用
    def _post_clean(self):
        pass

#短信登录form
class SmsloginForm(forms.Form):
    role = forms.ChoiceField(
        label="角色",
        required=True,  # 表示必须填写
        choices=(("1", "管理员"), ("2", "客户")),
        widget=forms.Select(attrs={'class': 'form-control'}))

    mobile = forms.CharField(
        label="手机号",
        validators=[RegexValidator(r'^1[358]\d{9}$', '手机号需要是13or5or8开头的11位数字')],
        widget=forms.TextInput(attrs={'class': 'form-control', "placeholder": "手机号"}),
        required=True,  # 表示必须填写 默认为T 可以不写这个参数
    )
    code = forms.CharField(
    label="短信验证码",
    validators=[RegexValidator(r'^[0-9]{4}$', '短信验证码必须是4位数字')],# 正则校验
    required=True,  # 表示必须填写
    widget=forms.PasswordInput(attrs={'class': 'form-control', "placeholder": "短信验证码"})
    )


    def clean_code(self):
        # 2 获取form验证通过的手机、验证码 角色
        code = self.cleaned_data.get("code")
        mobile = self.cleaned_data.get("mobile")
        if not mobile: #没有表示校验失败
            return code
        # 3code验证  获取redis编码 redi获取的是字节 需要decode("utf-8")
        conn = get_redis_connection("default")
        cache_code = conn.get(mobile)
        if not cache_code:
            raise ValidationError("验证码不存在，失效")
        if code != cache_code.decode("utf-8"):
            raise ValidationError("不正确")
        return code

#仅仅用于手机号发送短信校验
class MobileForm(forms.Form):
    role = forms.ChoiceField(
        label="角色",
        required=True,  # 表示必须填写
        choices=(("1", "管理员"), ("2", "客户")),
        widget=forms.Select(attrs={'class': 'form-control'}))

    mobile = forms.CharField(
        label="手机号",
        required=True,
        validators=[RegexValidator(r'^1[358]\d{9}$', '手机号需要是13or5or8开头的11位数字')]
    )


    #验证手机号的函数 自动调用
    def clean_mobile(self):
        # 有顺序从role——mobile 校验 role校验失败 在当前函数使用cleaned_data就不能获取到role的值
        role = self.cleaned_data.get("role")
        mobile = self.cleaned_data.get("mobile")
        if not role: #没有表示校验失败
            return mobile
        #去数据库校验是否存在手机号
        if role == "1":  # 管理员
            uesr_object = models.Administrator.objects.filter(active=1, mobile=mobile).exists()  # exists是否存在
        elif role == "2":  # 用户
            uesr_object = models.Customer.objects.filter(active=1, mobile=mobile).exists()
        #如果没有手机号
        if not uesr_object:
            raise ValidationError("手机号不存在")
        return mobile


#用户等级视图的Form 用于添加内容（Form方法）
class AddForm(forms.Form):
    level = forms.CharField(initial="级别",
                               widget=forms.TextInput(attrs={'class':'form-control',"placeholder":"级别"}),
                               required=True,  # 表示必须填写
                               )
    percent = forms.CharField(initial="折扣",
                               widget=forms.TextInput(attrs={'class':'form-control',"placeholder":"折扣"}),
                               required=True,  # 表示必须填写
                              help_text="填入0-100整数表示百分比，如：90为90%"
                               )



#使用ModelForm实现  用户等级视图
class LeveModelForm(forms.ModelForm):
    class Meta:
        # 不用像forms.Form 一个个写字段，会自己生成字段 基于model定义的数据库代码转换
        # label 映射 数据库的verbose_name  required 映射 数据库的 null+blank 是否为空
        # help_text 映射 数据库的 help_text
        model = models.Level
        fields = ["title","percent"]
        #添加样式
        # widgets = {
        #     "title":forms.TextInput(attrs={'class':'form-control',"placeholder":"级别"}),
        #     "percent":forms.TextInput(attrs={'class':'form-control',"placeholder":"折扣"})
        # }

    # 添加样式 的通用方法 代替widgets
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        #  self.fields 返回一个字典 键对应字段名  {'title':对象,"percent":对象}
        for name, field in self.fields.items():
            # 找到每一个字段 都在attrs 添加样式 form-control
            field.widget.attrs['class'] = "form-control"
            # 找到每一个字段 都在placeholder 添加默认显示的值 field.label（对象的label属性）
            field.widget.attrs['placeholder'] = "请输入{}".format(field.label)

